package com.example.springlearning.to;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import static java.util.concurrent.TimeUnit.*;

/**
 * @auth 罗俊华
 * @Date 2022/8/3 9:59 下午
 */
@Slf4j
public class BatchOrderTo implements Delayed, IBatchOrderTo {


    private final List<OrderItemTo> orderIdSkuCountList = new CopyOnWriteArrayList<>();

    @Getter
    private final long skuId;

    private final LocalDateTime endTime;

    /**
     * 库存扣减的结果
     */
    private final AtomicInteger subtractStockResult = new AtomicInteger(WAITING_SUBTRACT);

    /**
     * 等待扣减库存
     */
    public static final int WAITING_SUBTRACT = 0;

    /**
     * 库存扣减成功
     */
    public static final int SUBTRACT_SUCCESS = 1;

    /**
     * 库存扣减失败
     */
    public static final int SUBTRACT_FAIL = 2;

    /**
     * 为订单批量扣库存时，部分订单扣库存成功
     */
    public static final int SOME_ORDER_SUBTRACT_SUCCESS = 3;

    public static final int MAX_QUERY_LOOP_COUNT = 12;

    /**
     * 累计扣除库存成功的数量
     */
    private final AtomicInteger subtractStockSuccessCount = new AtomicInteger(0);

    /**
     * 累计扣除库存失败的数量
     */
    private final AtomicInteger subtractStockFailCount = new AtomicInteger(0);

    private final CountDownLatch subtractFinished;

    public BatchOrderTo(long skuId, int delay, TimeUnit timeUnit) {
        this.skuId = skuId;
        this.endTime = LocalDateTime.now().plusNanos(timeUnit.toNanos(delay));
        subtractFinished = new CountDownLatch(1);
    }


    public void addCount(OrderItemTo orderItemTo) {
        orderIdSkuCountList.add(orderItemTo);
    }

    /**
     * 查询减库存的结果
     *
     * @return
     */
    @Override
    public boolean getSubtractStockResult() throws InterruptedException {

         /*   while (subtractStockResult.get() == WAITING_SUBTRACT) {
                if (subtractStockResult.get() == SUBTRACT_SUCCESS) {
                    return true;
                } else if (subtractStockResult.get() == SUBTRACT_FAIL) {
                    return false;
                } else if (subtractStockResult.get() == SOME_ORDER_SUBTRACT_SUCCESS) {
                    break;
                }
                wait();
            }*/

        subtractFinished.await();

        if (subtractStockResult.get() == SUBTRACT_SUCCESS) {
            return true;
        } else if (subtractStockResult.get() == SUBTRACT_FAIL) {
            return false;
        }
        throw new IllegalStateException("扣库存结果异常");
    }


    /**
     * 批量扣减库存成功
     */
    @Override
    public boolean batchSubtractStockSuccess() {


        boolean result = subtractStockResult.compareAndSet(WAITING_SUBTRACT, SUBTRACT_SUCCESS);
        if (result) {
            int allSkuCount = getCurrentAllSkuCount();
//            log.info("扣除总共【{}】件【{}】成功", allSkuCount, skuId);
            subtractStockSuccessCount.addAndGet(allSkuCount);

            subtractStockFinish();
        }
        return result;

    }

    @Override
    public int getCurrentAllSkuCount() {
        return orderIdSkuCountList.stream().map(OrderItemTo::getStock).reduce(0, Integer::sum);
    }

    /**
     * 批量扣减库存失败
     *
     * @return
     */
    @Override
    public boolean batchSubtractStockFail() {


        boolean result = subtractStockResult.compareAndSet(WAITING_SUBTRACT, SUBTRACT_FAIL);
        if (result) {
            int allSkuCount = getCurrentAllSkuCount();
//            log.warn("扣除总共【{}】件【{}】失败", allSkuCount, skuId);
            subtractStockFailCount.addAndGet(allSkuCount);

            subtractStockFinish();
        }
        return result;


    }

    @Override
    public long getDelay(TimeUnit unit) {
        return unit.toNanos(Duration.between(LocalDateTime.now(), endTime).toNanos());
    }

    @Override
    public int compareTo(Delayed o) {
        long otherDelay = o.getDelay(MILLISECONDS);
        long delay = getDelay(MILLISECONDS);
        return (int) (delay - otherDelay);
    }

    @Override
    public List<OrderItemTo> getOrderIdSkuCountList() {
        return new ArrayList<>(orderIdSkuCountList);
    }

    @Override
    public void subtractStockFinish() {
        subtractFinished.countDown();
    }

    @Override
    public boolean splitSubtractOrder() {
        return subtractStockResult.compareAndSet(WAITING_SUBTRACT, SUBTRACT_FAIL);
    }

    @Override
    public int getSubtractStockSuccessCount() {
        return subtractStockSuccessCount.get();
    }

    @Override
    public int getSubtractStockFailCount() {
        return subtractStockFailCount.get();
    }
}
